//The MIT License (MIT)
//
//Copyright (c) 2020 lihp1603
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in
//all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//THE SOFTWARE.

package monitor

import (
	"log"
	"sync"
	"time"
)

//func LogInfo(fmt string, args ...interface{}) {
//	log.Printf(fmt, args)
//}

func LogErr(fmt string, args ...interface{}) {
	log.Printf(fmt, args)
}

//参考srs的定义
const (
	SYS_UTIME_MILLISECONDS              = 1 * time.Millisecond //1ms
	SYS_UTIME_SECOND                    = 1 * time.Second
	SYS_CYCLE_INTERVAL                  = 1000 * SYS_UTIME_MILLISECONDS
	SYS_TIME_RESOLUTION_MS_TIMES        = 1
	SYS_CPU_STAT_RESOLUTION_TIMES       = 3
	SYS_DISK_STAT_RESOLUTION_TIMES      = 6
	SYS_MEMINFO_RESOLUTION_TIMES        = 6
	SYS_PLATFORM_INFO_RESOLUTION_TIMES  = 9
	SYS_NETWORK_DEVICE_RESOLUTION_TIMES = 9
	SYS_SELF_RESOLUTION_TIMES           = 3
)

type MonitorReportHander interface {
	DoReport(m *Monitor)
}

type MonitorServerOption struct {
	DiskCatalog      string //监测的默认磁盘目录路径
	DiskName         string //监测的磁盘设备名
	MonitorReportSec int64  //监测上报时间周期
}

var DefaultMonitorServerOption = MonitorServerOption{
	DiskCatalog:      "/",
	DiskName:         "sda",
	MonitorReportSec: 10}

//定义一个服务类
type MonitorServer struct {
	m             *Monitor
	reportHandler MonitorReportHander
	option        MonitorServerOption
	running       bool
	mlock         sync.Mutex
	wg            sync.WaitGroup
}

func NewMonitorServer(reporthander MonitorReportHander, option MonitorServerOption) (*MonitorServer, error) {
	m, err := NewMonitor(option.DiskCatalog, option.DiskName)
	if err != nil {
		return nil, err
	}
	ms := &MonitorServer{running: false, reportHandler: reporthander, option: option, m: m}
	return ms, nil
}

func (ms *MonitorServer) Start() {
	ms.mlock.Lock()
	defer ms.mlock.Unlock()
	ms.running = true
	go func() {
		ms.wg.Add(1)
		ms.cycle()
		ms.wg.Done()
	}()
}

func (ms *MonitorServer) Stop() {
	ms.mlock.Lock()
	defer ms.mlock.Unlock()
	ms.running = false
	ms.wg.Wait()
}

func (ms *MonitorServer) cycle() {
	for i := int64(0); i < 10000 && ms.running; i++ {
		if i >= 1000 {
			i = 0
		}
		//
		time.Sleep(SYS_CYCLE_INTERVAL)
		ms.handleCycle(i)
		if i%ms.option.MonitorReportSec == 0 {
			if ms.reportHandler != nil {
				ms.reportHandler.DoReport(ms.m)
			}
		}
	}
}

func (ms *MonitorServer) handleCycle(sys_cycle_interval_times int64) {
	if sys_cycle_interval_times%SYS_CPU_STAT_RESOLUTION_TIMES == 0 {
		if err := ms.m.GetSysStats().CpuMI.UpdateMonitorInfo(); err != nil {
			LogErr("cpu moniter info update:", err)
		}
	}
	if sys_cycle_interval_times%SYS_DISK_STAT_RESOLUTION_TIMES == 0 {
		if err := ms.m.GetSysStats().DiskMI.UpdateMonitorInfo(); err != nil {
			LogErr("disk moniter info update:", err)
		}
		if err := ms.m.GetSysStats().VmMI.UpdateMonitorInfo(); err != nil {
			LogErr("vmstat moniter info update:", err)
		}
	}
	if sys_cycle_interval_times%SYS_MEMINFO_RESOLUTION_TIMES == 0 {
		if err := ms.m.GetSysStats().MemMI.UpdateMonitorInfo(); err != nil {
			LogErr("memory moniter info update:", err)
		}
	}
	if sys_cycle_interval_times%SYS_PLATFORM_INFO_RESOLUTION_TIMES == 0 {
		if err := ms.m.GetSysStats().LoadavgMI.UpdateMonitorInfo(); err != nil {
			LogErr("loadavg moniter info update:", err)
		}
		if err := ms.m.GetSysStats().UptimeMI.UpdateMonitorInfo(); err != nil {
			LogErr("uptime moniter info update:", err)
		}
	}
	if sys_cycle_interval_times%SYS_NETWORK_DEVICE_RESOLUTION_TIMES == 0 {
		if err := ms.m.GetSysStats().NetDevMI.UpdateMonitorInfo(); err != nil {
			LogErr("network devices moniter info update:", err)
		}
	}
	if sys_cycle_interval_times%SYS_SELF_RESOLUTION_TIMES == 0 {
		if err := ms.m.GetSelfStats().UpdateMonitorInfo(); err != nil {
			LogErr("self process update monitor:", err)
		}
	}
}
